/**
Copyright (c) 2013 cnova

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

library SpringAnnotations requires SpringCore, optional SpringPreloader
    
	globals
		integer Spring_Bean_Prototype_Instance = 0
	endglobals
	
    //! textmacro bean takes NAME
        module autowire_$NAME$
            readonly static boolexpr Spring_Bean_SelfInject_Init = null
            readonly static boolexpr Spring_Bean_SelfInject_Filters = null
            readonly static boolexpr Spring_Bean_SelfInject_Properties = null
			
            readonly static integer array Spring_Bean_unitTypeIds
            readonly static integer Spring_Bean_N_unitTypeIds = 0
            readonly static string array Spring_Bean_unitNames
            readonly static integer Spring_Bean_N_unitNames = 0
            
            readonly static integer Spring_Bean_Object_Id = -1
            readonly static string Spring_Bean_Object_Name = ""
			
            readonly static boolean Spring_Bean_Has_Unit_Filters = false
			
            private static string BEAN_NAME = "$NAME$"
			readonly integer handleid
			
			method operator mute= takes boolean EEE returns nothing
				call Spring_Set_Bean_Enabled(this.handleid, EEE)
			endmethod
			method operator muted takes nothing returns boolean
				return Spring_Is_Bean_Enabled(this.handleid)
			endmethod
    //! endtextmacro
    
    //! textmacro bean_extends takes NAME, SUPERCLASS
        module autowire_$NAME$
            private static constant boolean extending = true
            private static string BEAN_NAME = "$NAME$"
            implement autowire_$SUPERCLASS$
    //! endtextmacro

	//! textmacro strongtyped 
		private static constant boolean strong_typed = true 
	//! endtextmacro
	
    //! textmacro singleton
            public static method create takes nothing returns thistype
                return 1
            endmethod
    //! endtextmacro
    
	//! textmacro event2 takes E, interceptor
			private static method $E$_Prototype takes nothing returns boolean
				call thistype(Spring_Current_Instance).$interceptor$()
				return false
			endmethod
			private static constant method $E$_Tester takes nothing returns boolean
				return true
			endmethod
	//! endtextmacro
	
    //! textmacro event takes E, interceptor
			private static method $E$_Prototype takes nothing returns boolean
				static if thistype.strong_typed then
					call thistype(Spring_Current_Instance).$interceptor$()
				else
					static if thistype.$interceptor$.exists then
						call thistype(Spring_Current_Instance).$interceptor$()
					endif
				endif
				return false
			endmethod
			
			private static constant method $E$_Tester takes nothing returns boolean
				static if not thistype.$interceptor$.exists then
					return false
				else
					return true
				endif
			endmethod
    //! endtextmacro

    //! textmacro filters
			static if not thistype.extending then
				private static method Spring_FILTERS_UnitTypeIds takes nothing returns boolean
					local integer i 

					set i = thistype.Spring_Bean_N_unitTypeIds - 1
					loop
						exitwhen 0 > i
						if GetUnitTypeId(GetFilterUnit()) == thistype.Spring_Bean_unitTypeIds[i] then
							return true
						endif
						set i = i - 1
					endloop
						
					set i = thistype.Spring_Bean_N_unitNames - 1
					loop
						exitwhen 0 > i
						if GetUnitName(GetFilterUnit()) == thistype.Spring_Bean_unitNames[i] then
							return true
						endif
						set i = i - 1
					endloop
					return false
				endmethod
			endif

            private static method injectFilters takes nothing returns boolean
				local boolean rval = false
    //! endtextmacro
	//! textmacro objectname takes I
	 		    set thistype.Spring_Bean_Object_Name = "$I$"
	//! endtextmacro
	//! textmacro objectnamevar takes I
	 		    set thistype.Spring_Bean_Object_Name = $I$
	//! endtextmacro
    //! textmacro objectid takes I
				set thistype.Spring_Bean_Object_Id = $I$
    //! endtextmacro
    //! textmacro unittypeid takes T
	            set rval = true
                set thistype.Spring_Bean_unitTypeIds[thistype.Spring_Bean_N_unitTypeIds] = $T$
                set thistype.Spring_Bean_N_unitTypeIds = thistype.Spring_Bean_N_unitTypeIds + 1
    //! endtextmacro
    //! textmacro unitnamevar takes T
	            set rval = true
                set thistype.Spring_Bean_unitNames[thistype.Spring_Bean_N_unitNames] = $T$
                set thistype.Spring_Bean_N_unitNames = thistype.Spring_Bean_N_unitNames + 1
    //! endtextmacro
    //! textmacro unitname takes T
	            set rval = true
                set thistype.Spring_Bean_unitNames[thistype.Spring_Bean_N_unitNames] = "$T$"
                set thistype.Spring_Bean_N_unitNames = thistype.Spring_Bean_N_unitNames + 1
    //! endtextmacro
    //! textmacro endfilters
				return rval
            endmethod
    //! endtextmacro
    
    //! textmacro properties 
            private static method injectProperties takes thistype this returns boolean             
    //! endtextmacro
    //! textmacro property takes VARNAME, VARVALUE
                set this.$VARNAME$ = $VARVALUE$
    //! endtextmacro
	//! textmacro propertybean takes VARNAME, BEANNAME
				set this.$VARNAME$ = Spring.getBean(GetFilterUnit(), "$BEANNAME$")
	//! endtextmacro
    //! textmacro endproperties 
				return true
            endmethod
    //! endtextmacro

    //! textmacro endbean 
			static if thistype.injectProperties.exists then
				private static method injectPropertiesWrapper takes nothing returns boolean
					 call thistype.injectProperties(Spring_Current_Instance)
					 return false
				endmethod
			endif

            private static method SelfInject takes nothing returns boolean
                local integer u = GetHandleId(GetFilterUnit())
                local thistype this
                local integer this_handle

                static if thistype.extending then
                    // subclass level, get implementation created prior
                    set this            = Spring_Bean_Prototype_Instance
                    set this_handle     = this.handleid
                else
                    // we at superclass level
                    set this = thistype.create()
                    set this_handle = Spring_Create_Handle()
                    set Spring_Bean_Prototype_Instance = this  
					set this.handleid = this_handle
					call Spring_Save_Bean_Context(u, thistype.BEAN_NAME, this)
                endif

                call Spring_AddObjectIdFilter(this_handle, thistype.Spring_Bean_Object_Id)

				
				static if thistype.injectProperties.exists then
					if thistype.Spring_Bean_SelfInject_Properties == null then
						set thistype.Spring_Bean_SelfInject_Properties = Condition (function thistype.injectPropertiesWrapper)
					else
						set thistype.Spring_Bean_SelfInject_Properties = And (Condition (function thistype.injectPropertiesWrapper), thistype.Spring_Bean_SelfInject_Properties)
					endif
				endif
				
				static if not thistype.extending then
					if thistype.Spring_Bean_SelfInject_Properties != null then
						call Spring_Save_Handle(this, this_handle, EVENT_ENTER_PRE_ENTER_MAP, u, thistype.Spring_Bean_SelfInject_Properties) 
					endif
				endif

				static if thistype.EVENT_ENTER_MAP_Prototype.exists then
					if thistype.EVENT_ENTER_MAP_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ENTER_MAP, u,    Condition (function thistype.EVENT_ENTER_MAP_Prototype)) 
					endif
				endif
				
				static if thistype.EVENT_LEVEL_Prototype.exists then
					if thistype.EVENT_LEVEL_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_LEVEL, u,    Condition (function thistype.EVENT_LEVEL_Prototype)) 
					endif
				endif
				static if thistype.EVENT_CHANGE_OWNER_Prototype.exists then
					if thistype.EVENT_CHANGE_OWNER_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_CHANGE_OWNER, u,    Condition (function thistype.EVENT_CHANGE_OWNER_Prototype)) 
					endif
				endif
				static if thistype.EVENT_UNIT_DIE_Prototype.exists then
					if thistype.EVENT_UNIT_DIE_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_UNIT_DIE, u,    Condition (function thistype.EVENT_UNIT_DIE_Prototype)) 
					endif
				endif

				static if thistype.EVENT_ISSUED_ORDER_Prototype.exists then
					if thistype.EVENT_ISSUED_ORDER_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ISSUED_ORDER, u,    Condition (function thistype.EVENT_ISSUED_ORDER_Prototype)) 
					endif
				endif
				static if thistype.EVENT_ISSUED_POINT_ORDER_Prototype.exists then
					if thistype.EVENT_ISSUED_POINT_ORDER_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ISSUED_POINT_ORDER, u,    Condition (function thistype.EVENT_ISSUED_POINT_ORDER_Prototype)) 
					endif
				endif
				static if thistype.EVENT_ISSUED_TARGET_ORDER_Prototype.exists then
					if thistype.EVENT_ISSUED_TARGET_ORDER_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ISSUED_TARGET_ORDER, u,    Condition (function thistype.EVENT_ISSUED_TARGET_ORDER_Prototype)) 
					endif
				endif
				static if thistype.EVENT_ISSUED_UNIT_ORDER_Prototype.exists then
					if thistype.EVENT_ISSUED_UNIT_ORDER_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ISSUED_UNIT_ORDER, u,    Condition (function thistype.EVENT_ISSUED_UNIT_ORDER_Prototype)) 
					endif
				endif

                static if thistype.EVENT_SPELL_EFFECT_Prototype.exists then
					if thistype.EVENT_SPELL_EFFECT_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_EFFECT, u,  Condition (function thistype.EVENT_SPELL_EFFECT_Prototype))
					endif
				endif
                static if thistype.EVENT_SPELL_CHANNEL_Prototype.exists then
					if thistype.EVENT_SPELL_CHANNEL_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_CHANNEL, u, Condition (function thistype.EVENT_SPELL_CHANNEL_Prototype))
					endif
				endif
                static if thistype.EVENT_SPELL_LEARN_Prototype.exists then
					if thistype.EVENT_SPELL_LEARN_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_LEARN, u,   Condition (function thistype.EVENT_SPELL_LEARN_Prototype))
					endif
				endif
                static if thistype.EVENT_SPELL_CAST_Prototype.exists then
					if thistype.EVENT_SPELL_CAST_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_CAST, u,    Condition (function thistype.EVENT_SPELL_CAST_Prototype))
					endif
				endif
                static if thistype.EVENT_SPELL_ENDCAST_Prototype.exists then
					if thistype.EVENT_SPELL_ENDCAST_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_ENDCAST, u, Condition (function thistype.EVENT_SPELL_ENDCAST_Prototype))
					endif
				endif
                static if thistype.EVENT_SPELL_FINISH_Prototype.exists then
					if thistype.EVENT_SPELL_FINISH_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_SPELL_FINISH, u,  Condition (function thistype.EVENT_SPELL_FINISH_Prototype))
					endif
				endif

                static if thistype.EVENT_REINCARNATION_START_Prototype.exists then
					if thistype.EVENT_REINCARNATION_START_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_REINCARNATION_START, u,  Condition (function thistype.EVENT_REINCARNATION_START_Prototype))
					endif
				endif
                static if thistype.EVENT_REINCARNATION_FINISH_Prototype.exists then
					if thistype.EVENT_REINCARNATION_FINISH_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_REINCARNATION_FINISH, u,  Condition (function thistype.EVENT_REINCARNATION_FINISH_Prototype)) 
					endif
				endif
                
                static if thistype.EVENT_ATTACK_Prototype.exists then
					if thistype.EVENT_ATTACK_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ATTACK, u,  Condition (function thistype.EVENT_ATTACK_Prototype)) 
					endif
 			    endif
                static if thistype.EVENT_ATTACKED_Prototype.exists then
					if thistype.EVENT_ATTACKED_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_ATTACKED, u,  Condition (function thistype.EVENT_ATTACKED_Prototype)) 
					endif
				endif
                
                static if thistype.EVENT_DAMAGE_Prototype.exists then
					if thistype.EVENT_DAMAGE_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_DAMAGE, u,  Condition (function thistype.EVENT_DAMAGE_Prototype)) 
					endif
				endif
                static if thistype.EVENT_DAMAGED_Prototype.exists then
					if thistype.EVENT_DAMAGED_Tester() then
						call Spring_Save_Handle(this, this_handle, EVENT_DAMAGED, u,  Condition (function thistype.EVENT_DAMAGED_Prototype)) 
					endif	
				endif
                
                return true
            endmethod
            
            static if not thistype.extending then  
            private static method initAfter takes nothing returns boolean
                local boolexpr final
                local integer i 

				// if bean name filter was set, override the id
				if thistype.Spring_Bean_Object_Name != "" then
					set i = GetObjectId(thistype.Spring_Bean_Object_Name)
					if i != 0 then
						set thistype.Spring_Bean_Object_Id = i
					elseif thistype.Spring_Bean_Object_Id == -1 then
						set thistype.Spring_Bean_Object_Id = 0
					endif
				endif

                if thistype.Spring_Bean_SelfInject_Filters != null then
                    // filters come first, then the init function
                    set final = And(thistype.Spring_Bean_SelfInject_Filters, thistype.Spring_Bean_SelfInject_Init)
                else
                    set final = thistype.Spring_Bean_SelfInject_Init
                endif 

                if not thistype.Spring_Bean_Has_Unit_Filters then
                    call Spring_AddNullFilter(final)
                else
                    set i = thistype.Spring_Bean_N_unitTypeIds -1
                    loop
                        exitwhen 0 > i
                        call Spring_AddUnitTypeIdFilter(final, thistype.Spring_Bean_unitTypeIds[i])
                        set i = i - 1
                    endloop

                    set i = thistype.Spring_Bean_N_unitNames - 1
                    loop
                        exitwhen 0 > i
                        call Spring_AddUnitNameFilter(final, thistype.Spring_Bean_unitNames[i])
                        set i = i - 1
                    endloop
                endif
                set final = null
                return false
            endmethod
            endif
            
            private static method onInit takes nothing returns nothing
                static if thistype.injectFilters.exists then
                    set thistype.Spring_Bean_Has_Unit_Filters = thistype.injectFilters()
                endif

				// if root bean and filters() macro was used, means Spring_FILTERS_UnitTypeIds now exists
				static if not thistype.extending and thistype.injectFilters.exists then 
					if thistype.Spring_Bean_Has_Unit_Filters then
						set thistype.Spring_Bean_SelfInject_Filters = Condition(function thistype.Spring_FILTERS_UnitTypeIds)  
					endif
				endif 
				
                // subclass constructurs always come after superclass
                if thistype.Spring_Bean_SelfInject_Init == null then
                    set thistype.Spring_Bean_SelfInject_Init = Condition(function thistype.SelfInject)
                else
                    set thistype.Spring_Bean_SelfInject_Init = And(thistype.Spring_Bean_SelfInject_Init, Condition(function thistype.SelfInject))
                endif
                
                static if not thistype.extending then
                    call Spring_Add_On_Init (Condition(function thistype.initAfter))
                endif

            endmethod
        endmodule
    //! endtextmacro
    
endlibrary
